﻿using CC.Extending;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CC.Common
{
    public class CsvHelper
    {
        public static void ExportObjectListToCsv<T>(string file,IEnumerable<T> list,Encoding encoding)
        {
            string titleEn = "";
            var props = list.FirstOrDefault().GetType().GetProperties();
            foreach (var prop in props)
            {

                titleEn += "," + prop.Name;
            }
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(titleEn);
            foreach (var obj in list)
            {
                string line = "";
                foreach (var prop in props)
                {
                    object value = prop.GetValue(obj, null);
                    line += "," + value.ToString();
                }
                sb.AppendLine(line);
            }
            File.WriteAllText(file, sb.ToString(), encoding);
        }
        public static List<T>ReadCsvToObjectList<T>(string file, Encoding encoding)
        {
            List<T> list = new List<T>();
            var props = typeof(T).GetProperties();
            var lines = File.ReadAllLines(file, encoding);
            if (lines.Length <= 0)
            {
                throw new Exception($"读到空文件: {file}");
            }
            //读入title
            var titles = lines.First().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            //读入数据，每行一个实例
            for (int i = 1 ; i < lines.Length; i++)
            {
                var segs = lines[i].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                T obj = System.Activator.CreateInstance<T>();
                for (int p = 0; p < props.Length; p++)
                {
                    var prop = props[p];
                    int prpIndex = Array.FindIndex(titles, t=>t == prop.Name);
                    if (prpIndex < 0) continue;
                    if (prop.PropertyType.IsEnum)
                    {
                        var val = (Enum.Parse(prop.PropertyType, segs[i]));
                        prop.SetValue(obj, val, null);
                    }
                    else 
                    {
                        prop.SetValue(obj, segs[prpIndex], null);
                    }
                }
                list.Add(obj);
            }
            return list;
        }
        public static void ExportDataTableToCsv(string file,DataTable table,Encoding encoding)
        {
            string titleEn = "";
            foreach (DataColumn col in table.Columns)
            {
                titleEn += "," + col.ColumnName;
            }
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(titleEn);

            for (int r = 0; r < table.Rows.Count; r++)
            {
                var row = table.Rows[r];
                
                for (int i = 0; i < row.ItemArray.Length; i++)
                {
                    sb.Append(", " + row.ItemArray[i].ToString());

                }
                sb.AppendLine();
            }
            File.WriteAllText(file, sb.ToString(), encoding);
        }
        /// <summary>
        /// 将数据输出为csv文件(逗号分隔的文件)
        /// </summary>
        /// <param name="file">目标文件</param>
        /// <param name="colTitles">数据列标题，标题数量应该与数据列数相同，如果不相同，则报异常。无标题输入null</param>
        /// <param name="datas">要保存的数据。一般而言，每组数据的长度应该一样。如果不一样，将截取最短长度来保存</param>
        public static void ExportToCsv<T>(string file,string[] colTitles,params T[][] datas)
        {
            if (datas.Length <= 0) return;
            if(colTitles!=null&&colTitles.Length!=datas.Length)
            {
                throw (new Exception("输出数据到CSV文件：数据列标题数量应该与数据列数相同。如果无标题输入null"));
            }
            int dataLength = datas.Select(d => d.Length).Min();
            StringBuilder sb = new StringBuilder();
            if(colTitles!=null)
            {
                string titleLine="";//注释行
                foreach (var title in colTitles)
                {
                    titleLine += ", " + title;
                }
                sb.AppendLine("!");
                sb.Append(titleLine.Substring(1));
            }
            for (int i = 0; i < dataLength; i++)
            {
                string dataLine = "";
                for (int c = 0; c < datas.Length; c++)
                {
                    dataLine += ", " + datas[c][i].ToString();
                }
                sb.AppendLine(dataLine.Substring(1));
            }
            File.WriteAllText(file, sb.ToString(), Encoding.UTF8);
        }
        public static DataTable ReadDataTableFromCsv(string file, Encoding encoding = null)
        {
            if (encoding == null)
                encoding = Encoding.GetEncoding("gb2312");
            string[] lines = File.ReadAllLines(file, encoding);
            if (lines.Length <= 0) return null;
            DataTable table = new DataTable();

            //查找列标题，以及数据开始行
            int startRow = 0;
            for (int i = 0; i < lines.Length; i++)
            {
                string line = lines[i];
                if (lines.Length <= i + 3) return null;//数据行数太少
                if (string.IsNullOrEmpty(line)) continue;
                if (Regex.IsMatch(lines[i].TrimStart(), @"^[+-]{0,1}\d"))//连续三行以数字开头，视为数据开始
                {
                    if (Regex.IsMatch(lines[i + 1].TrimStart(), @"^[+-]{0,1}\d"))//连) Char.IsDigit(续三行以数字开头，视为数据开始
                    {
                        if (Regex.IsMatch(lines[i + 2].TrimStart(), @"^[+-]{0,1}\d"))//连续三行以数字开头，视为数据开始
                        {
                            startRow = i;
                            string[] strs = lines[i].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            if (i == 0)//首行是数据，说明是纯数据文件，就以Item1...为列标题
                            {
                                for (int c = 0; c < strs.Length; c++)
                                {
                                    table.Columns.Add("Item" + c);
                                }
                                break;
                            }
                            else
                            {//往回找标题行：列数与数据列数相同的行
                                for (int l = i - 1; l >= 0; l++)
                                {
                                    string[] segs = lines[l].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    if (segs.Length == strs.Length)
                                    {
                                        for (int s = 0; s < segs.Length; s++)
                                        {
                                            if (table.Columns.Contains(segs[s])) table.Columns.Add(segs[s] + s);
                                            else table.Columns.Add(segs[s]);
                                        }
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
            }
            if (table.Columns == null || table.Columns.Count <= 0)
            {
                return null;
            }

            for (int i = startRow; i < lines.Length; i++)
            {
                if (!string.IsNullOrEmpty(lines[i]))
                {
                    string[] strs = lines[i].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    var row = table.Rows.Add();
                    int endCol = table.Columns.Count < strs.Length ? table.Columns.Count : strs.Length;
                    for (int c = 0; c < endCol; c++)
                    {
                        row[c] = strs[c].ToDouble();
                    }
                }

            }
            return table;
        }
        /// <summary>
        /// 读取 频率-值 数据对，频率自动/1e6变成MHz
        /// </summary>
        /// <param name="file"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static PointF[] ReadDataToFreqVsValue(string file, Encoding encoding = null)
        {
            DataTable table = CsvHelper.ReadDataTableFromCsv(file, encoding);
            List<PointF> sparam = new List<PointF>();

            if (table != null && table.Rows.Count > 0)
            {
                foreach (DataRow row in table.Rows)
                {
                    if(row.ItemArray.Length>1)
                    {
                        float freq = (float)(Convert.ToDouble(row[0]) / 1e6);
                        float value = Convert.ToSingle(row[1]);
                        sparam.Add(new PointF(freq, value));
                    }
                }
            }
            return sparam.ToArray();
        }
    }
}
